package cn.dida;

import cn.dida.core.*;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.*;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.env.Environment;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.config.annotation.*;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver;

import javax.servlet.*;
import java.util.EnumSet;
import java.util.List;
import java.util.Properties;

/**
 * 系统启动入口，Spring容器配置、启动入口
 * @author weiwei 
 */
@Configuration
@EnableWebMvc
@EnableScheduling
@EnableAsync
@PropertySource({"classpath:app.properties"})
@ComponentScan(basePackages = {"cn.dida"})
@ImportResource({"classpath:orm.xml"})
public class BootStrap implements WebApplicationInitializer {
    private Log logger = LogFactory.getLog(getClass());

    @Autowired
    private Environment env;

    @Bean
    public static PropertySourcesPlaceholderConfigurer PropertySourcesPlaceholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }

    /**
     * 系统启动入口
     * */
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
        rootContext.register(BootStrap.class);
        servletContext.addListener(new ContextLoaderListener(rootContext));
        servletContext.addListener(new ServletContextListener() {
            @Override
            public void contextInitialized(ServletContextEvent contextEvent) {
                logger.info("Context Initialized!");
            }

            @Override
            public void contextDestroyed(ServletContextEvent contextEvent) {
                logger.info("Context Destroyed!");
            }
        });


        servletContext.addFilter("WrapRequestFilter", new WrapRequestFilter()).addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");

        servletContext.addServlet("dispatcher", new DispatcherServlet(rootContext)).addMapping("/");
    }

    
    /**
     *  mvc相关配置
     *  @return WebMvcConfigurerAdapter
     * */
    @Bean
    public WebMvcConfigurerAdapter webMvcConfigurerAdapter() {
        return new WebMvcConfigurerAdapter() {
            //Json视图解析器，使用FastJson替换spring默认的Jackson
            @Override
            public void configureViewResolvers(ViewResolverRegistry registry) {
                registry.enableContentNegotiation();
            }

            @Override
            public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
                FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
                FastJsonConfig fastJsonConfig = fastJsonHttpMessageConverter.getFastJsonConfig();
                fastJsonConfig.setSerializerFeatures(SerializerFeature.WriteNonStringKeyAsString);
                converters.add(fastJsonHttpMessageConverter);
            }

            // 拦截器配置
            @Override
            public void addInterceptors(InterceptorRegistry registry) {
                //全局拦截器
                registry.addInterceptor(new GlobalInterceptor()).addPathPatterns("/**").excludePathPatterns("/callback","/customerredbagscallback");
                //登录检查拦截器
                registry.addInterceptor(new LoginCheckInterceptor()).addPathPatterns("/**").excludePathPatterns("/login","/callback","/customerredbagscallback");
                //权限检查拦截器
                registry.addInterceptor(new AuthInterceptor()).addPathPatterns("/**").excludePathPatterns("/login", "/logout", "/error","/callback","/customerredbagscallback");
                //资源树拦截器
                registry.addInterceptor(new UserResTreePrepareInterceptor()).addPathPatterns("/**").excludePathPatterns("/login", "/logout","/callback","/customerredbagscallback");
                //操作日志拦截器
                registry.addInterceptor(optionLogInterceptor()).addPathPatterns("/**").excludePathPatterns("/login", "/logout", "/error","/callback","/customerredbagscallback");
                super.addInterceptors(registry);
            }

            @Override
            public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
                configurer.enable();
            }
        };
    }

    /**
     * 页面文件配置
     * @return FreeMarkerConfigurer
     * */
    @Bean
    public FreeMarkerConfigurer freeMarkerConfig() {
        FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
        configurer.setTemplateLoaderPath("/WEB-INF/templates/");
        configurer.setDefaultEncoding("UTF-8");

        Properties properties = new Properties();
        //properties.setProperty("classic_compatible", "true");
        //properties.setProperty("template_exception_handler", "html_debug");
        properties.setProperty("template_exception_handler", "rethrow");
        properties.setProperty("number_format", "#");
        configurer.setFreemarkerSettings(properties);

        return configurer;
    }

    /**
     * 视图解析配置
     * @return FreeMarkerViewResolver
     * */
    @Bean
    public FreeMarkerViewResolver freeMarkerViewResolver() {
        FreeMarkerViewResolver resolver = new FreeMarkerViewResolver();
        resolver.setCache(false);
        resolver.setPrefix("page/");
        resolver.setSuffix(".ftl");
        resolver.setContentType("text/html;charset=UTF-8");
        return resolver;
    }

    /**
     * 操作日志拦截器
     * @return OptionLogInterceptor
     * */
    @Bean
    public OptionLogInterceptor optionLogInterceptor() {
        return new OptionLogInterceptor();
    }

    /**
     * 线程池
     * @return ThreadPoolTaskExecutor
     */
    @Bean
    public ThreadPoolTaskExecutor ThreadPoolTaskExecutor() {
        ThreadPoolTaskExecutor pool = new ThreadPoolTaskExecutor();
        pool.setCorePoolSize(5);
        pool.setMaxPoolSize(10);
        pool.setWaitForTasksToCompleteOnShutdown(true);
        return pool;
    }

    
    /**
     * 上传文件解析器
     * @return CommonsMultipartResolver
     * */
    @Bean(name = "multipartResolver")
    public CommonsMultipartResolver standardServletMultipartResolver() {
        CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
        multipartResolver.setMaxUploadSize(1024 * 1024 * 5 * 5);
        multipartResolver.setMaxUploadSizePerFile(1024 * 1024 * 5);
        multipartResolver.setMaxInMemorySize(1024 * 1024);
        return multipartResolver;
    }

    /**
     * 方法日志代理
     * @return BeanNameAutoProxyCreator
     * */
    @Bean
    public BeanNameAutoProxyCreator beanNameAutoProxyCreator() {
        BeanNameAutoProxyCreator bean = new BeanNameAutoProxyCreator();
        bean.setBeanNames("interactDao", "commentDao", "inviteDao");
        bean.setInterceptorNames("BusinessEventInterceptor");
        return bean;
    }

    /**
     *  系统启动监听器，用于系统启动完成后的初始化操作
     * @return ApplicationListener<ContextRefreshedEvent>
     */
    @Bean
    public ApplicationListener<ContextRefreshedEvent> applicationListener() {
        return new ApplicationListener<ContextRefreshedEvent>() {
            @Override
            public void onApplicationEvent(ContextRefreshedEvent event) {
                ApplicationContext applicationContext = event.getApplicationContext();
                try {
                    logger.info("SpringContext Refreshed!");
                    SystemInitializer systemInitializer = new SystemInitializer(applicationContext);
                    systemInitializer.init();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };
    }
}